home *** CD-ROM | disk | FTP | other *** search
/ Meeting Pearls 1 / Meeting Pearls Vol 1 (1994).iso / installed_progs / disk / amicdrom / cdrom.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-18  |  15.7 KB  |  613 lines

  1. /* cdrom.c:
  2.  *
  3.  * Basic interaction with the CDROM drive.
  4.  *
  5.  * ----------------------------------------------------------------------
  6.  * This code is (C) Copyright 1993,1994 by Frank Munkert.
  7.  * All rights reserved.
  8.  * This software may be freely distributed and redistributed for
  9.  * non-commercial purposes, provided this notice is included.
  10.  * ----------------------------------------------------------------------
  11.  * History:
  12.  * 
  13.  * 18-May-94   fmu   New drive model: MODEL_CDU_8002 (= Apple CD 150).
  14.  * 17-May-94   fmu   Sense length 20 instead of 18 (needed by ALF controller).
  15.  * 17-Feb-94   fmu   Added support for Toshiba 4101.
  16.  * 06-Feb-94   dmb   - Fixed bug in Test_Unit_Ready() trackdisk support.
  17.  *                   - Fixed bug in Open_CDROM (size of request)
  18.  *                   - Added function Clear_Sector_Buffers().
  19.  * 01-Jan-94   fmu   Added function Data_Tracks() for multisession support.
  20.  * 11-Dec-93   fmu   - Memory type can now be chosen by the user.
  21.  *                   - Addional parameter p_direction for Do_SCSI_Command().
  22.  *                   - Start_Play_Audio() now plays all tracks.
  23.  *                   - Mode_Select() instead of Select_XA_Mode().
  24.  *                   - Support for CDROM drives with 512, 1024 or 2048 bytes
  25.  *                     per block.
  26.  * 06-Dec-93   fmu   New drive type DRIVE_SCSI_2.
  27.  * 09-Nov-93   fmu   Added Select_XA_Mode.
  28.  * 23-Oct-93   fmu   Open_CDROM now returns an error code that tell what
  29.  *                   went wrong.
  30.  * 09-Oct-93   fmu   SAS/C support added.
  31.  * 03-Oct-93   fmu   New buffering algorithm.
  32.  * 27-Sep-93   fmu   Added support for multi-LUN devices.
  33.  * 24-Sep-93   fmu   - SCSI buffers may now reside in fast or chip memory.
  34.  *                   - TD_CHANGESTATE instead of CMD_READ in Test_Unit_Ready
  35.  */
  36.  
  37. #include <string.h>
  38.  
  39. #include <clib/exec_protos.h>
  40. #include <clib/alib_protos.h>
  41.  
  42. #ifdef AZTEC_C
  43. #include <pragmas/exec_lib.h>
  44. #endif
  45. #ifdef LATTICE
  46. #include <pragmas/exec_pragmas.h>
  47. #endif
  48. #if defined (_DCC) && defined (REGISTERED)
  49. #include <pragmas/exec_pragmas.h>
  50. extern struct Library *SysBase;
  51. #endif
  52.  
  53. #include <devices/trackdisk.h>
  54.  
  55. #include <limits.h>
  56.  
  57. #include "cdrom.h"
  58.  
  59. int g_cdrom_errno;
  60. int g_ignore_blocklength = FALSE;
  61.  
  62. void Determine_Drive_Type (CDROM *p_cd)
  63. {
  64.   t_inquiry_data data;
  65.   char buf[33];
  66.   
  67.   p_cd->scsi_compliance = 1;
  68.   p_cd->model = MODEL_ANY;
  69.  
  70.   if (!Inquire (p_cd, &data))
  71.     return;
  72.  
  73.   if ((data.version & 0x7) >= 2)
  74.     p_cd->scsi_compliance = 2;
  75.  
  76.   if (strncmp (data.vendor, "TOSHIBA", 7) == 0) {
  77.     memcpy (buf, data.product, 32);
  78.     buf[32] = 0;
  79.     if (strstr (buf, "3401") || strstr (buf, "4101"))
  80.       p_cd->model = MODEL_TOSHIBA_3401;
  81.   } else if (strncmp (data.vendor, "SONY", 4) == 0) {
  82.     memcpy (buf, data.product, 32);
  83.     buf[32] = 0;
  84.     if (strstr (buf, "CDU-8002"))
  85.       p_cd->model = MODEL_CDU_8002;
  86.   }
  87. }
  88.  
  89. CDROM *Open_CDROM (char *p_device, int p_scsi_id, int p_use_trackdisk,
  90.            unsigned long p_memory_type,
  91.            int p_std_buffers, int p_file_buffers)
  92. {
  93.   CDROM *cd;
  94.   int i;
  95.   int bufs = p_std_buffers + p_file_buffers + 1;
  96.   
  97.   g_cdrom_errno = CDROMERR_NO_MEMORY;
  98.  
  99.   cd = AllocMem (sizeof (CDROM),
  100.                MEMF_PUBLIC | MEMF_CLEAR | p_memory_type);
  101.   if (!cd)
  102.     return NULL;
  103.  
  104.   cd->std_buffers = p_std_buffers;
  105.   cd->file_buffers = p_file_buffers;
  106.  
  107.   cd->buffer_data = AllocMem (SCSI_BUFSIZE * bufs + 15,
  108.                     MEMF_PUBLIC | p_memory_type);
  109.   if (!cd->buffer_data) {
  110.     Cleanup_CDROM (cd);
  111.     return NULL;
  112.   }
  113.  
  114.   cd->buffers = AllocMem (sizeof (unsigned char *) * bufs, MEMF_PUBLIC);
  115.   if (!cd->buffers) {
  116.     Cleanup_CDROM (cd);
  117.     return NULL;
  118.   }
  119.   
  120.   cd->current_sectors = AllocMem (sizeof (long) * bufs, MEMF_PUBLIC);
  121.   if (!cd->current_sectors) {
  122.     Cleanup_CDROM (cd);
  123.     return NULL;
  124.   }
  125.  
  126.   cd->last_used = AllocMem (sizeof (unsigned long) * p_std_buffers,
  127.                   MEMF_PUBLIC | MEMF_CLEAR);
  128.   if (!cd->last_used) {
  129.     Cleanup_CDROM (cd);
  130.     return NULL;
  131.   }
  132.   
  133.   /* make the buffer quad-word aligned. This greatly helps 
  134.    * performance on '040-powered systems with DMA SCSI
  135.    * controllers.
  136.    */
  137.  
  138.   cd->buffers[0] = (UBYTE *)(((ULONG)cd->buffer_data + 15) & ~15);
  139.  
  140.   for (i=1; i<bufs; i++)
  141.     cd->buffers[i] = cd->buffers[0] + i * SCSI_BUFSIZE;
  142.  
  143.   cd->port = CreateMsgPort ();
  144.   if (!cd->port) {
  145.     g_cdrom_errno = CDROMERR_MSGPORT;
  146.     Cleanup_CDROM (cd);
  147.     return NULL;
  148.   }
  149.  
  150.   cd->scsireq = CreateIORequest (cd->port, sizeof (struct IOExtTD));
  151.   if (!cd->scsireq) {
  152.     g_cdrom_errno = CDROMERR_IOREQ;
  153.     Cleanup_CDROM (cd);
  154.     return NULL;
  155.   }
  156.  
  157.   if (OpenDevice ((UBYTE *) p_device, p_scsi_id,
  158.                   (struct IORequest *) cd->scsireq, 0)) {
  159.     g_cdrom_errno = CDROMERR_DEVICE;
  160.     Cleanup_CDROM (cd);
  161.     return NULL;
  162.   }
  163.  
  164.   cd->device_open = TRUE;
  165.  
  166.   for (i=0; i<bufs; i++)
  167.     cd->current_sectors[i] = -1;
  168.  
  169.   cd->use_trackdisk = p_use_trackdisk;
  170.   cd->t_changeint = -1;
  171.   cd->t_changeint2 = -2;
  172.  
  173.   /* The LUN is the 2nd digit of the SCSI id number: */
  174.   cd->lun = (p_scsi_id / 10) % 10;
  175.  
  176.   /* 'tick' is incremented every time a sector is accessed. */
  177.   cd->tick = 0;
  178.  
  179.   g_cdrom_errno = 0;
  180.  
  181.   Determine_Drive_Type (cd);
  182.  
  183.   if (g_ignore_blocklength) {
  184.     cd->block_length = 0;
  185.     cd->blocking_factor = 0;
  186.   } else {
  187.     cd->block_length = Block_Length (cd);
  188.     switch (cd->block_length) {
  189.     case 2048:
  190.       cd->blocking_factor = 0;
  191.       break;
  192.     case 1024:
  193.       cd->blocking_factor = 1;
  194.       break;
  195.     case 512:
  196.       cd->blocking_factor = 2;
  197.       break;
  198.     case 0:
  199.       cd->blocking_factor = 0;
  200.       break;
  201.     default:
  202.       g_cdrom_errno = CDROMERR_BLOCKSIZE;
  203.       Cleanup_CDROM (cd);
  204.       return NULL;
  205.     }
  206.   }
  207.  
  208.   return cd;
  209. }
  210.  
  211. int Do_SCSI_Command (CDROM *p_cd, unsigned char *p_buf, long p_buf_length,
  212.              unsigned char *p_command, int p_length, int p_direction)
  213. {
  214.   int bufs = p_cd->std_buffers + p_cd->file_buffers + 1;
  215.  
  216.   p_cd->scsireq->io_Length   = sizeof (struct SCSICmd);
  217.   p_cd->scsireq->io_Data     = (APTR) &p_cd->cmd;
  218.   p_cd->scsireq->io_Command  = HD_SCSICMD;
  219.  
  220.   p_cd->cmd.scsi_Data        = (UWORD *) p_buf;
  221.   p_cd->cmd.scsi_Length      = p_buf_length;
  222.   p_cd->cmd.scsi_Flags       = SCSIF_AUTOSENSE | p_direction;
  223.   p_cd->cmd.scsi_SenseData   = (UBYTE *) p_cd->sense;
  224.   p_cd->cmd.scsi_SenseLength = 20;
  225.   p_cd->cmd.scsi_SenseActual = 0;
  226.   p_cd->cmd.scsi_Command     = (UBYTE *) p_command;
  227.   p_cd->cmd.scsi_CmdLength   = p_length;
  228.  
  229.   p_command[1] |= p_cd->lun << 5;
  230.  
  231.   DoIO ((struct IORequest *) p_cd->scsireq);
  232.   if (p_cd->cmd.scsi_Status) {
  233.     int i;
  234.     for (i=0; i<bufs; i++)
  235.       p_cd->current_sectors[i] = -1;
  236.     return 0;
  237.   } else
  238.     return 1;
  239. }
  240.  
  241. int Read_From_Drive (CDROM *p_cd, unsigned char *p_buf, long p_buf_length,
  242.              long p_sector, int p_number_of_sectors)
  243. {
  244.   static unsigned char cmd[10] = { 0x28, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  245.   int bufs = p_cd->std_buffers + p_cd->file_buffers + 1;
  246.  
  247. #ifdef DEBUG_SECTORS
  248.   extern void *dbprintf (char *, ...);
  249.  
  250.   if (p_number_of_sectors == 1)
  251.     dbprintf ("[%ld]", p_sector);
  252.   else
  253.     dbprintf ("[%ld-%ld]", p_sector, p_sector + p_number_of_sectors - 1);
  254. #endif
  255.  
  256.   if (p_cd->use_trackdisk) {
  257.     p_cd->scsireq->io_Length   = 2048 * p_number_of_sectors;
  258.     p_cd->scsireq->io_Data     = (APTR) p_buf;
  259.     p_cd->scsireq->io_Offset   = (ULONG) p_sector * 2048;
  260.     p_cd->scsireq->io_Command  = CMD_READ;
  261.  
  262.     DoIO ((struct IORequest *) p_cd->scsireq);
  263.     if (p_cd->scsireq->io_Error) {
  264.       int i;
  265.       for (i=0; i<bufs; i++)
  266.         p_cd->current_sectors[i] = -1;
  267.       return 0;
  268.     } else
  269.       return 1;
  270.   } else {
  271.     long sector = p_sector << p_cd->blocking_factor;
  272.     cmd[5] = sector & 0xff;
  273.     cmd[4] = (sector >> 8) & 0xff;
  274.     cmd[3] = (sector >> 16) & 0x1f;
  275.  
  276.     cmd[8] = p_number_of_sectors << p_cd->blocking_factor;
  277.  
  278.     return Do_SCSI_Command (p_cd, p_buf, p_buf_length, cmd, sizeof (cmd),
  279.                     SCSIF_READ);
  280.   }
  281. }
  282.  
  283. /* Read one sector from the CDROM drive.
  284.  */
  285.  
  286. int Read_Sector (CDROM *p_cd, long p_sector)
  287. {
  288.   int status;
  289.   int i;
  290.   int maxbuf = p_cd->std_buffers;
  291.   int loc;
  292.  
  293.   p_cd->tick++;
  294.  
  295.   for (i=0; i<maxbuf; i++)
  296.     if (p_cd->current_sectors[i] == p_sector) {
  297.       p_cd->buffer = p_cd->buffers[i];
  298.       p_cd->last_used[i] = p_cd->tick;
  299.       return 1;
  300.     }
  301.  
  302.   /* find an empty buffer position: */
  303.   for (loc=0; loc<maxbuf; loc++)
  304.     if (p_cd->current_sectors[loc] == -1)
  305.       break;
  306.  
  307.   if (loc==maxbuf) {
  308.     /* no free buffer position; remove the buffer that is unused
  309.        for the longest time: */
  310.     unsigned long oldest_tick = ULONG_MAX;
  311.     unsigned long tick;
  312.  
  313.     for (loc=0, i=0; i<maxbuf; i++) {
  314.       tick = p_cd->last_used[i];
  315.       if (tick < oldest_tick)
  316.         loc = i, oldest_tick = tick;
  317.     }
  318.   }
  319.  
  320.   status = Read_From_Drive (p_cd, p_cd->buffers[loc], SCSI_BUFSIZE,
  321.                   p_sector, 1);
  322.   if (status) {
  323.     p_cd->current_sectors[loc] = p_sector;
  324.     p_cd->buffer = p_cd->buffers[loc];
  325.     p_cd->last_used[loc] = p_cd->tick;
  326.   }
  327.  
  328.   return status;
  329. }
  330.  
  331. /* Read_Contiguous_Sectors uses the 'file buffers' instead of the
  332.  * 'standard buffers'. Additionaly, more than one sector may be read
  333.  * with a single SCSI command. This may cause a substantial increase
  334.  * in speed when reading large files.
  335.  */
  336.  
  337. int Read_Contiguous_Sectors (CDROM *p_cd, long p_sector, long p_last_sector)
  338. {
  339.   int status;
  340.   int i;
  341.   int maxbuf = p_cd->std_buffers + p_cd->file_buffers;
  342.   int len;
  343.  
  344.   for (i=p_cd->std_buffers; i<maxbuf; i++)
  345.     if (p_cd->current_sectors[i] == p_sector) {
  346.       p_cd->buffer = p_cd->buffers[i];
  347.       return 1;
  348.     }
  349.  
  350.   if (p_last_sector <= p_sector)
  351.     len = 1;
  352.   else {
  353.     len = p_last_sector - p_sector + 1;
  354.     if (len > p_cd->file_buffers)
  355.       len = p_cd->file_buffers;
  356.     if (len > 255)
  357.       len = 255;
  358.   }
  359.  
  360.   status = Read_From_Drive (p_cd, p_cd->buffers[p_cd->std_buffers],
  361.                   SCSI_BUFSIZE * len, p_sector, len);
  362.   if (status) {
  363.     long sector = p_sector;
  364.     for (i=p_cd->std_buffers; len; i++, len--)
  365.       p_cd->current_sectors[i] = sector++;
  366.     p_cd->buffer = p_cd->buffers[p_cd->std_buffers];
  367.   }
  368.  
  369.   return status;
  370. }
  371.  
  372. int Test_Unit_Ready (CDROM *p_cd)
  373. {
  374.   if (p_cd->use_trackdisk) {
  375.     p_cd->scsireq->io_Command = TD_CHANGENUM;
  376.     if (!DoIO ((struct IORequest *) p_cd->scsireq)) {
  377.       if (p_cd->scsireq->io_Error==0)
  378.         p_cd->t_changeint = p_cd->scsireq->io_Actual;
  379.     }
  380.     p_cd->scsireq->io_Command = TD_CHANGESTATE;
  381.     if (!DoIO ((struct IORequest *) p_cd->scsireq)) {
  382.       if (p_cd->scsireq->io_Error==0 &&
  383.           p_cd->scsireq->io_Actual==0)
  384.         return TRUE;
  385.     }
  386.     return FALSE;
  387.   } else {
  388.     int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  389.     static unsigned char cmd[6] = { 0, 0, 0, 0, 0, 0 };
  390.  
  391.     return Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], SCSI_BUFSIZE,
  392.                     cmd, 6, SCSIF_READ);
  393.   }
  394. }
  395.  
  396. int Is_XA_Mode_Disk (CDROM *p_cd)
  397. {
  398.   static unsigned char cmd[10] = { 0xC7, 3, 0, 0, 0, 0, 0, 0, 0, 0 };
  399.   int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  400.  
  401.   if (!Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], 4,
  402.               cmd, 10, SCSIF_READ))
  403.     return FALSE;
  404.  
  405.   return *(p_cd->buffers[dummy_buf]) == 0x20;
  406. }
  407.  
  408. int Mode_Select (CDROM *p_cd, int p_mode, int p_block_length)
  409. {
  410.   static unsigned char cmd[6] = { 0x15, 0x10, 0, 0, 12, 0 };
  411.   static unsigned char mode[12] = { 0, 0, 0, 8,
  412.                     0, 0, 0, 0, 0, 0, 0, 0 };
  413.   int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  414.  
  415.   if (p_cd->use_trackdisk)
  416.     return FALSE;
  417.  
  418.   p_cd->block_length = p_block_length;
  419.   switch (p_cd->block_length) {
  420.   case 2048:
  421.     p_cd->blocking_factor = 0;
  422.     break;
  423.   case 1024:
  424.     p_cd->blocking_factor = 1;
  425.     break;
  426.   case 512:
  427.     p_cd->blocking_factor = 2;
  428.     break;
  429.   }
  430.  
  431.   mode[4] = p_mode;
  432.   mode[9] = p_block_length >> 16;
  433.   mode[10] = (p_block_length >> 8) & 0xff;
  434.   mode[11] = p_block_length & 0xff;
  435.  
  436.   memcpy (p_cd->buffers[dummy_buf], mode, sizeof (mode));
  437.   return Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], sizeof (mode),
  438.                 cmd, 6, SCSIF_WRITE);
  439. }
  440.  
  441. int Inquire (CDROM *p_cd, t_inquiry_data *p_data)
  442. {
  443.   static unsigned char cmd[6] = { 0x12, 0, 0, 0, 96, 0 };
  444.   int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  445.   
  446.   if (p_cd->use_trackdisk)
  447.     return FALSE;
  448.  
  449.   if (!Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], 96,
  450.               cmd, 6, SCSIF_READ))
  451.     return FALSE;
  452.   
  453.   memcpy (p_data, p_cd->buffers[dummy_buf], sizeof (*p_data));
  454.   return 1;
  455. }
  456.  
  457. #define TOC_SIZE 804
  458.  
  459. t_toc_data *Read_TOC (CDROM *p_cd, t_toc_header *p_toc_header)
  460. {
  461.   static unsigned char cmd[10] = { 0x43, 0, 0, 0, 0, 0, 0,
  462.                      TOC_SIZE >> 8, TOC_SIZE & 0xff, 0 };
  463.   int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  464.  
  465.   if (p_cd->use_trackdisk)
  466.     return NULL;
  467.  
  468.   if (!Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], TOC_SIZE,
  469.               cmd, 10, SCSIF_READ))
  470.     return NULL;
  471.  
  472.   memcpy (p_toc_header, p_cd->buffers[dummy_buf], sizeof (*p_toc_header));
  473.   return (t_toc_data *) (p_cd->buffers[dummy_buf] + 4);
  474. }
  475.  
  476. int Has_Audio_Tracks (CDROM *p_cd)
  477. {
  478.   t_toc_header hdr;
  479.   t_toc_data *toc;
  480.   int i, len;
  481.   
  482.   if (!(toc = Read_TOC (p_cd, &hdr)))
  483.     return FALSE;
  484.  
  485.   len = hdr.length / 8;
  486.   for (i=0; i<len; i++) {
  487.     if (toc[i].track_number != 0xAA &&
  488.         !(toc[i].flags & 4))
  489.       return toc[i].track_number;
  490.   }
  491.   return FALSE;
  492. }
  493.  
  494. /*
  495.  * Create a buffer containing the start addresses of all data tracks
  496.  * on the disk.
  497.  *
  498.  * Returns:
  499.  *  number of tracks or -1 on error.
  500.  */
  501.  
  502. int Data_Tracks (CDROM *p_cd, unsigned long** p_buf)
  503. {
  504.   int cnt=0;
  505.   t_toc_header hdr;
  506.   t_toc_data *toc;
  507.   int i, j, len;
  508.   
  509.   if (!(toc = Read_TOC (p_cd, &hdr)))
  510.     return -1;
  511.  
  512.   len = hdr.length / 8;
  513.  
  514.   /* count number of data tracks: */
  515.   for (i=0; i<len; i++)
  516.     if (toc[i].track_number != 0xAA && (toc[i].flags & 4))
  517.       cnt++;
  518.  
  519.   if (cnt == 0)
  520.     return 0;
  521.  
  522.   /* allocate memory for output buffer: */
  523.   *p_buf = (unsigned long*) AllocVec (cnt * sizeof (unsigned long*),
  524.                         MEMF_PUBLIC);
  525.   if (!*p_buf)
  526.     return -1;
  527.  
  528.   /* fill output buffer: */
  529.   for (i=0, j=0; i<len; i++)
  530.     if (toc[i].track_number != 0xAA && (toc[i].flags & 4))
  531.       (*p_buf)[j++] = toc[i].address;
  532.  
  533.   return cnt;
  534. }
  535.  
  536. int Start_Play_Audio (CDROM *p_cd)
  537. {
  538.   static unsigned char cmd[10] = { 0x48, 0, 0, 0, 0, 1, 0, 99, 99, 0 };
  539.   int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  540.  
  541.   if (p_cd->use_trackdisk ||
  542.       (p_cd->scsi_compliance == 1 && p_cd->model == MODEL_ANY))
  543.     return FALSE;
  544.  
  545.   if (p_cd->model == MODEL_CDU_8002)
  546.     cmd[0] = 0xC9;
  547.  
  548.   cmd[4] = Has_Audio_Tracks (p_cd);
  549.  
  550.   return Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], 0,
  551.                     cmd, 10, SCSIF_WRITE);
  552. }
  553.  
  554. int Stop_Play_Audio (CDROM *p_cd)
  555. {
  556.   static unsigned char cmd[6] = { 0x1B, 0, 0, 0, 0, 0 };
  557.   int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  558.  
  559.   if (p_cd->use_trackdisk)
  560.     return FALSE;
  561.  
  562.   return Do_SCSI_Command (p_cd, p_cd->buffers[dummy_buf], 0,
  563.                     cmd, 6, SCSIF_WRITE);
  564. }
  565.  
  566. int Block_Length (CDROM *p_cd)
  567. {
  568.   static unsigned char cmd[6] = { 0x1A, 0, 1, 0, 100, 0 };
  569.   int dummy_buf = p_cd->std_buffers + p_cd->file_buffers;
  570.   unsigned char *buf = p_cd->buffers[dummy_buf];
  571.  
  572.   if (p_cd->use_trackdisk)
  573.     return 0;
  574.   
  575.   if (!Do_SCSI_Command (p_cd, buf, 100,    cmd, 6, SCSIF_READ))
  576.     return 0;
  577.  
  578.   if (buf[3] == 0)
  579.     return 0;
  580.   
  581.   return (buf[9]<<16) + (buf[10]<<8) + buf[11];
  582. }
  583.  
  584. void Cleanup_CDROM (CDROM *p_cd)
  585. {
  586.   int bufs = p_cd->std_buffers + p_cd->file_buffers + 1;
  587.  
  588.   if (p_cd->device_open)
  589.     CloseDevice ((struct IORequest *) p_cd->scsireq);
  590.   if (p_cd->scsireq)
  591.     DeleteIORequest (p_cd->scsireq);
  592.   if (p_cd->port)
  593.     DeleteMsgPort (p_cd->port);
  594.   if (p_cd->last_used)
  595.     FreeMem (p_cd->last_used, sizeof (unsigned long) * p_cd->std_buffers);
  596.   if (p_cd->current_sectors)
  597.     FreeMem (p_cd->current_sectors, sizeof (long) * bufs);
  598.   if (p_cd->buffers)
  599.     FreeMem (p_cd->buffers, sizeof (unsigned char *) * bufs);
  600.   if (p_cd->buffer_data)
  601.     FreeMem (p_cd->buffer_data, SCSI_BUFSIZE * bufs + 15);
  602.   FreeMem (p_cd, sizeof (CDROM));
  603. }
  604.  
  605. void Clear_Sector_Buffers (CDROM *p_cd)
  606. {
  607.   int i;
  608.   int bufs = p_cd->std_buffers + p_cd->file_buffers + 1;
  609.  
  610.   for (i=0; i<bufs; i++)
  611.     p_cd->current_sectors[i] = -1;
  612. }
  613.